package infra.starters;



import processing.core.*;
import org.NooLab.utilities.logging.PrintLog;
import org.NooLab.utilities.timing.DelayFor;
import org.NooLab.utilities.timing.DelayNotificationIntf;

import org.NooLab.glue.instances.*;
import org.NooLab.glue.components.*;
import org.NooLab.glue.components.pkg.TaskPackage;
import org.NooLab.glue.subscription.FilterPackageIntf;
import org.NooLab.glue.transaction.Transaction;
 
 
 
import infra.common.DataContainer;
import infra.common.FilterExample;
 



public class MsgReceptorInstance extends PApplet {
	

	private static final long serialVersionUID = -8855166507553000451L;


	RecInstance recInstance;
	 
	
	public void setup(){
		 
		
		background( 228,228,128);
		// start this in its own thread...
		recInstance = new RecInstance();
		
	}
	
	
	
	public void draw(){
		 
	}
 
 
 
	public void keyPressed() {
		 

		if (key=='r'){
			recInstance.getInstance().connect() ;
		}
		
		if (key=='u'){
			recInstance.getInstance().disconnect() ;
		}
  
		if (key=='x'){
			if (recInstance!=null){
				recInstance.getInstance().disconnect();
			}
			System.exit(0);
		}
	}
}


/**
 * 
 * 
 */
class RecInstance implements Runnable, TaskReceiverIntf{ 

	// =================================

	// object references ..............
	ParticipantFactory factory ;
	MessageBoardFactoryProperties factoryProperties ;
	// this is one of two differences between sources and receptors: just use another interface
	ParticipantReceptorIntf participant ;
	 
	FilterExample filter;
	
	// main variables / properties ....
	long transactID=-1;
	
	
	// volatile variables .............
	
	// helper objects
	Thread iThrd; 
	PrintLog out = new PrintLog(2,false);
	
	
	// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
	public RecInstance(){
		// we start then instance into a thread, which is independent from the PApplet
		(new Thread(this,"RecInstance-main")).start() ;
	}	 
	// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
	
	public void run() {
		 create();
	}

	private void create(){
		 
		try{

			factoryProperties = new MessageBoardFactoryProperties();

			factoryProperties.setHomePath("D:/dev/java/data/test/mb/");
			factoryProperties.setProtocolId(MessageBoardFactoryProperties.protocolUDP);
			factoryProperties.setProtocolId(MessageBoardFactoryProperties.protocolTCP);
			factoryProperties.setProtocolId(MessageBoardFactoryProperties.protocolHREST);
			
			// false: only local addresses
			factoryProperties.setRemoteInstancesFlag(false);
			// define the type of the client
			factoryProperties.setTypeOfInstance(MessageBoardFactoryProperties.variant_RECEPTOR);

			filter = new FilterExample();
			factoryProperties.setFilter((FilterPackageIntf) filter);

			// ------------------------------------------------------------
			factory = new ParticipantFactory(factoryProperties, this);

			factory.config().setActiveReceiptsExchange(true);
			factory.config().setInstanceAsUnique(false);
			factory.config().setName("testReceptor0");
			factory.config().setDefaultDocType("doc");

			participant = (ParticipantReceptorIntf) (factory.getInstance());

			participant.connect();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
	  
	// this is used by the application object, which is hosting this instance (linkage to GUI) 
	public ParticipantReceptorIntf getInstance(){
		return participant;
	}

	// =============== interfaced methods ===============
	
	@Override
	public void interControlMessage(String str) {

		out.printErr(2, "RecInstance :: interControlMessage()\n\r"+ str) ;
	}

	@Override
	public void handlingControlRequest(long transactionID, String controlName) {

		if (controlName.contentEquals("cancel")){
			out.printErr(2, "RECEPTOR: Handling cancel request...") ;
		}
		
		
	}

	
	
	
	@Override
	public void taskProvider(TaskPackage taskpackage) {
		 
		out.printErr(2, "MsgReceptorInstance :: RecInstance :: resultsProvider()");	
		_digestingReceivedMsg( taskpackage ) ;
		
	}
	
	
	
	// =============== local methods ===============
	
	private void _digestingReceivedMsg( TaskPackage taskPackage ){
		
		int state=0;
		TaskPackage resultPackage ;
		Transaction mTransact;
		DataContainer dataobj;
		String str, ctype ;
		
		
		
												out.print(5,"\nRECEPTOR is working on provided task object...\n");
	
		if (taskPackage==null){
		
			// some message ...
			return ;
		}
		
		
		
		// the TaskPackage contains the complete mirrored transaction, as it is known by 
		// the MessageReceptor after receiving the message
		// we need this in order to reply using the correct reference, then the MessageBoard can
		// return the reply to the correct SOURCE
		mTransact = taskPackage.getTransactionMirror() ;
		transactID = taskPackage.getTransactionID() ;
		
		dataobj = (DataContainer) taskPackage.getDataObj() ;
		
		ctype = taskPackage.getContentType() ;
		str = taskPackage.getDataString() ;
												    out.print(2,"\nRECEPTOR is working on provided task object...\n");
	
		
													out.print(2,"transaction ID of task (type of content: "+ctype+") : "+ mTransact.getTransactionID() ) ;
													out.print(2,"content of task data :\n               "+ str) ;
													out.print(2,"     ... simulating calculation time") ;
	    delay(2000);	
	 // we may also send simple state messages
	    participant.startProcessNotification(transactID);
		//  in ReceptorParticipant
	    
		
				
		
		state = participant.getTransactionControlState() ;
		
		resultPackage = participant.getResultPackage();
		
		if (state == Transaction.TS_TASK_CANCELED){

			resultPackage.setTransactionID( transactID );
			resultPackage.setTypeOfProceedings("stop::code="+Transaction.TS_ERR_STOPPED);
			
			// 
			out.print(2,"     ... calculations canceled.") ;
		} else {
			// preparing resultPackage
			out.print(2,"     ... calculations finished.") ;
			
			resultPackage.setTransactionID(transactID);
			resultPackage.setTypeOfProceedings("result");
			
			resultPackage.setContentType(ctype);
			

			resultPackage.setDataString("String processed: "+ str.toUpperCase().replace("E", "I").replace("A", "I"));
					

			// for transferring untyped data: resultPackage.setData(object,
			// identifier)
			// use identifier to indicate the cast of the object

			resultPackage.setContentType("RESULT");
			// resultPackage is defined in super-class "MessageBoardParticipant"
		}
		
	}

	private void delay( int millis ){
		
		try {
			Thread.currentThread();
			Thread.sleep(millis);
		} catch (InterruptedException e) {
		}
	}




	  

}
 
  
 
